package com.icarsaas.saas.master.web;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.db.sql.SqlExecutor;
import com.icarsaas.saas.common.enums.StatusEnum;
import com.icarsaas.saas.common.page.SoulPage;
import com.icarsaas.saas.common.utils.ResultVoUtil;
import com.icarsaas.saas.common.utils.StatusUtil;
import com.icarsaas.saas.common.utils.ToolUtil;
import com.icarsaas.saas.common.vo.ResultVo;
import com.icarsaas.saas.component.actionLog.action.SaveAction;
import com.icarsaas.saas.component.actionLog.action.StatusAction;
import com.icarsaas.saas.component.actionLog.annotation.ActionLog;
import com.icarsaas.saas.component.actionLog.annotation.EntityParam;
import com.icarsaas.saas.component.fileUpload.FileUploadUtil;
import com.icarsaas.saas.master.model.MasterTenant;
import com.icarsaas.saas.master.model.MasterTenantDetail;
import com.icarsaas.saas.master.service.MasterTenantDetailService;
import com.icarsaas.saas.master.service.MasterTenantService;
import com.icarsaas.saas.master.utils.MasterDbUtil;
import com.icarsaas.saas.tenant.config.DataSourceBasedMultiTenantConnectionProviderImpl;
import com.icarsaas.saas.tenant.system.model.FileUpload;
import com.icarsaas.saas.tenant.system.service.UploadService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.HtmlUtils;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;


@Controller @RequestMapping(value = "/masterTenant/") @Slf4j
@Api(tags="租户管理模块")
public class MasterTenantController {
	@Autowired private MasterTenantService masterTenantService;
	@Autowired private MasterTenantDetailService masterTenantDetailService;
	@Autowired @Qualifier("dataSourceBasedMultiTenantConnectionProviderImpl") private DataSourceBasedMultiTenantConnectionProviderImpl provider;
	@Autowired private UploadService uploadService;

	@GetMapping("/masterTenantList") //@RequiresPermissions("system:dict:status")
	public String masterTenantList() {
		return "/masterTenant/masterTenantList";
	}

	@PostMapping("listSoulTable") @ResponseBody
	public Object listSoulTable(SoulPage<Map<String, Object>> page, @RequestBody Map<String, Object> params) {
		page.setParams(params, page);
		page = masterTenantService.listSoulData(page, params);
		return page;
	}

	@ModelAttribute
	public MasterTenant get(@RequestParam(required = false) Long id) {
		MasterTenant entity = null;
		if (id != null) entity = masterTenantService.get(id);
		else entity = new MasterTenant();
		return entity;
	}
	/**
	 * 跳转到编辑页面
	 */
	@GetMapping({"masterTenantForm", "masterTenantForm/{id}"})
	public String masterTenantForm(@RequestParam(value = "id", required = false) MasterTenant entity, Model model) {
		if (entity == null) entity = new MasterTenant();
		model.addAttribute("entity", entity);
		// model.addAttribute("logoPath",  "/upload/logo/20220306/14f738c24cb5467688006ee3e50f9b5e.jpg");
		return "/masterTenant/masterTenantForm";
	}
	/**
	 * 保存添加/修改的数据
	 */
	@PostMapping({"/saveEntity"}) @ResponseBody @ApiOperation(value = "保存租户信息")
	@ActionLog(name = "租户管理", message = "租户信息：${tenantName}", action = SaveAction.class)
	public ResultVo<?> saveEntity(@EntityParam MasterTenant entity/*, @RequestParam(value = "refId", required = false) String refId*/) {
		if (StringUtils.isNotEmpty(entity.getUrl())) {//特殊符号转义
			String url = HtmlUtils.htmlUnescape(entity.getUrl());
			entity.setUrl(url);
		}
		boolean flag_new = entity.getId() == null ? true : false;
		masterTenantService.save(entity);
		if (flag_new) {//新增状态下应该同步更新一下附件的随机refId,或者初始化明细表
			//uploadService.updateRefId(refId, entity.getId().toString());
			MasterTenantDetail detail = entity.getMasterTenantDetail();
			if (detail == null) {
				detail = new MasterTenantDetail();
				detail.setMasterTenant(entity);
				detail = masterTenantDetailService.save(detail);
				entity.setMasterTenantDetail(detail);
				masterTenantService.save(entity);
			}
		}
		return ResultVoUtil.SAVE_SUCCESS;
	}

    /**
     * 删除记录
	 * @param ids 删除的数据id
	 * @param param 状态标识，必须带
	 * @return
     */
	@PostMapping("/deleteEntity") @ResponseBody
	@ActionLog(name = "租户管理", message = "删除租户信息：${tenantName}", action = StatusAction.class)
	public ResultVo<?> deleteEntity(@RequestParam(value = "ids", required = false) List<Long> ids
			, @RequestParam(value = "param", required = false) String param) {
		// 更新状态
		if (ids != null && ids.size() > 0) {
			ids.forEach(id -> {
				masterTenantService.delete(id);
			});
			return ResultVoUtil.success("操作成功");
		} else {
			return ResultVoUtil.error("操作失败，请重试!");
		}
	}

	/**
	 * 设置一条或者多条数据的状态
	 */
	@PostMapping("status") @ResponseBody
	@ActionLog(name = "租户状态", action = StatusAction.class)
	public ResultVo<?> updateStatus(@RequestParam(value = "ids", required = false) List<Long> ids
			, @RequestParam(value = "param", required = false) String param) {
		// 更新状态
		StatusEnum statusEnum = StatusUtil.getStatusEnum(param);
		if (masterTenantService.updateStatus(statusEnum, ids)) {
			return ResultVoUtil.success(statusEnum.getMessage() + "成功");
		} else {
			return ResultVoUtil.error(statusEnum.getMessage() + "失败，请重新操作");
		}
	}

	/**
	 * 跳转到详细页面
	 */
	@GetMapping("/detail/{id}")
	public String toDetail(@PathVariable("id") MasterTenant entity, Model model){
		model.addAttribute("entity", entity);
		return "/masterTenant/masterTenantDetail";
	}

	/**
	 * 跳转到详细页面
	 */
	@GetMapping("/init/{id}")
	public String init(@PathVariable("id") MasterTenant entity, Model model){
		// 默认创建SQL
		StringBuilder sqlCreate = new StringBuilder("CREATE DATABASE IF NOT EXISTS ");
		String url = entity.getUrl();
		String table_name = "";
		if (StringUtils.isNotEmpty(url)) {
			table_name = ToolUtil.subString(url, "3306/", "?");//获取配置的数据名称
			sqlCreate.append(table_name).append(";").append(System.getProperty("line.separator"));
		}
		String user_table = "USE " + table_name + ";" + System.getProperty("line.separator");
		sqlCreate.append(user_table);//声明使用该数据库
		StringBuilder sqlInit = new StringBuilder(user_table);
		//读取默认初始化文件并写入
		try {
			ClassPathResource classPathResource = new ClassPathResource("sql/tenant.sql");
			InputStream inputStream = classPathResource.getInputStream();
			String table_create = IoUtil.read(inputStream, CharsetUtil.UTF_8);
			sqlCreate.append(table_create);
			// SQL init 初始化
			classPathResource = new ClassPathResource("sql/init.sql");
			inputStream = classPathResource.getInputStream();
			String table_init = IoUtil.read(inputStream, CharsetUtil.UTF_8);
			sqlInit.append(table_init);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		entity.setSqlCreate(sqlCreate.toString());
		entity.setSqlInit(sqlInit.toString());
		// 默认授权SQL
		String username = entity.getUsername(), pass = entity.getPassword();
		StringBuilder sqlGrant = new StringBuilder("CREATE USER '" + username +"'@'localhost' IDENTIFIED BY '" + pass + "';").append(System.getProperty("line.separator"));
		String auth = "`" + table_name + "`.* TO '" + username + "'@'localhost';";
		sqlGrant.append("GRANT SELECT, INSERT, UPDATE, REFERENCES, DELETE, CREATE, DROP, ALTER" +
				", INDEX, TRIGGER, CREATE VIEW, SHOW VIEW, EXECUTE, ALTER ROUTINE, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES" +
				", EVENT ON " + auth).append(System.getProperty("line.separator"));
		sqlGrant.append("GRANT GRANT OPTION ON " + auth);
		entity.setSqlGrant(sqlGrant.toString());

		model.addAttribute("entity", entity);
		return "/masterTenant/masterTenantInit";
	}

	/**
	 * 跳转到详细页面
	 */
	@PostMapping("initSql")  @ResponseBody
	@ActionLog(name = "租户初始化", action = SaveAction.class)
	public ResultVo<?> initSql(@EntityParam MasterTenant entity, Model model) {
		String sqlCreate = entity.getSqlCreate();
		String sqlInit = entity.getSqlInit();
		String sqlGrant = entity.getSqlGrant();
		if (StringUtils.isNotEmpty(sqlCreate) || StringUtils.isNotEmpty(sqlGrant) || StringUtils.isNotEmpty(sqlInit)) {
			Connection conn = null;
			try {
				conn = new MasterDbUtil().getConnection();
				boolean flag = false;
				if (StringUtils.isNotEmpty(sqlCreate)) {
					SqlExecutor.execute(conn, sqlCreate);
					log.info("执行建库SQL:" + sqlCreate);
					flag = true;
				}
				if (StringUtils.isNotEmpty(sqlGrant)) {
					SqlExecutor.execute(conn, sqlGrant);
					log.info("执行授权SQL:" + sqlGrant);
					flag = true;
				}
				if (StringUtils.isNotEmpty(sqlInit)) {
					SqlExecutor.execute(conn, sqlInit);
					log.info("执行初始化SQL:" + sqlInit);
					flag = true;
				}
				if (flag) {//更新状态
					if (entity.getInit() != 1) {
						entity.setInit(new Byte("1"));
						masterTenantService.save(entity);
					}
					provider.addTenant(entity.getTenantId());
				}
			} catch (SQLException e) {
				ResultVoUtil.error("操作失败，请联系管理员");
			}
		}
		return ResultVoUtil.success("执行成功");
	}

	/**
	 * 上传web格式图片
	 */
	@PostMapping("/uploadLogo") @ResponseBody
	public ResultVo<?> uploadLogo(@RequestParam("file") MultipartFile file, @RequestParam("refId") String refId
			, @RequestParam(value = "type", required = false) String type, @RequestParam(value = "path", required = false) String path) {
		// 创建Upload实体对象
		if (StringUtils.isEmpty(type)) type = "logo";
		if (StringUtils.isEmpty(path)) path = "/logo";
		FileUpload upload = FileUploadUtil.getFile(file, refId, type, path);
		log.info("附件信息：RefId={}, type={}, path={}", refId, type, path);
		try {
			FileUploadUtil.transferTo(file, upload);
			uploadService.save(upload);
			MasterTenantDetail detail = masterTenantDetailService.get(refId, null);
			detail.setLogo(upload.getPath());
			masterTenantDetailService.save(detail);
			return ResultVoUtil.successZero(upload);
		} catch (IOException | NoSuchAlgorithmException e) {
			return ResultVoUtil.error("上传图片失败");
		}
	}

}
